/*
 *  Copyright (C) 2004 Cidero, Inc.
 *
 *  Permission is hereby granted to any person obtaining a copy of 
 *  this software to use, copy, modify, merge, publish, and distribute
 *  the software for any non-commercial purpose, subject to the
 *  following conditions:
 *  
 *  The above copyright notice and this permission notice shall be included
 *  in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY IN CONNECTION WITH THE SOFTWARE.
 * 
 *  File: $RCSfile: SBSketcher.java,v $
 *
 */

package com.cidero.server.roku;

import java.io.*;
import java.net.*;
import java.util.logging.Logger;

import com.cidero.util.MrUtil;

/**
 * Thread to communicate with Roku Sketch interface running on port 4444
 * Used to draw text strings (Song Artist/Title from net radio streams) 
 * on display 
 */
public class SBSketcher
{
  private static Logger logger = Logger.getLogger("com.cidero.server.roku");

  private final static int SB_CONTROL_PORT = 4444;

  String ipAddr;
  Socket socket;
  PrintStream printStream;
  SBReadThread readThread;
  
  /** 
   * Constructor
   */
  public SBSketcher( String ipAddr )
  {
    this.ipAddr = ipAddr;
    connect();
  }
  
  /**
   * Connect to roku TCP interface 4444
   *
   * Separate asynchronous reader thread is created to read back 
   * responses from Soundbridge device (they are just discarded for now -
   * no error checking is done).
   */
  public synchronized void connect()
  {
    logger.fine("Connecting to Roku Soundbridge TCP interface at " 
                + ipAddr + ":" + SB_CONTROL_PORT );

    if( socket == null )
    {
      try
      {
        //
        // If host is in IP '.' notation, create a InetAddr here and use
        // that to open the socket. This allows the Socket constructor to
        // bypass some name resolution logic than can introduce significant
        // latency under Windows when TCP/IP NETBIOS name resolution is in
        // effect.
        //
        // Split pattern of "\D" means split when not a digit ('.'). Helps
        // screen out non-numeric hosts with '.''s  (e.g. java.sun.com.net) 
        String[] hostByteStrings = ipAddr.split("\\D");
        if( hostByteStrings.length == 4 )
        {
          byte[] hostBytes = new byte[4];
          for( int n = 0 ; n < 4 ; n++ )
            hostBytes[n] = (byte)Integer.parseInt( hostByteStrings[n] );

          //System.out.println("-!!--post: Creating Inet4Address for " +
          //            host );
          InetAddress inetAddr = InetAddress.getByAddress( ipAddr,
                                                           hostBytes );

          socket = new Socket( inetAddr, SB_CONTROL_PORT );
        }
        else
        {
          socket = new Socket( ipAddr, SB_CONTROL_PORT );
        }
        
        OutputStream out = socket.getOutputStream();
        printStream = new PrintStream( out );

        readThread = new SBReadThread( socket );
        readThread.start();
        
      }
      catch( Exception e )
      {
        logger.warning( "Error connecting to Soundbridge control interface on port " +
                        SB_CONTROL_PORT );
        socket = null;
        return;
      }
    }
    
    logger.fine("Connected ok");
  }

  /**
   * Send a message to the sketch command processor.
   *
   * @param   cmd  
   *
   */ 
  public synchronized boolean sendCmd( String cmd )
  {
    //if( socket == null )
    //  connect();

    if( socket == null )
    {
      logger.warning("sendMsg: not connected");
      return false;
    }
      
    long promptCount = readThread.getSketchPromptCount();
    
    logger.fine("Sending cmd: " + cmd );
    
    try 
    {
      printStream.print( cmd );
      printStream.flush();
    }
    catch( Exception e )
    {
      System.out.println( e );
      return false;
    }
    
    int waitCount = 0;
    while( readThread.getSketchPromptCount() == promptCount )
    {
      MrUtil.sleep(500);
      if( ++waitCount > 10 ) 
      {
        logger.warning("Timeout waiting for sketch prompt after cmd");
        return false;
      }
    }
    
    return true;
    
    //System.out.print( "Sent msg: " + cmd );
  }

  public synchronized boolean enterSketchMode()
  {
    // Issue 'sketch' command to enter text drawing mode
    return sendCmd("sketch\n");
  }

  public synchronized boolean quitSketchMode()
  {
    // Issue 'sketch' command to enter text drawing mode
    return sendCmd("quit\n");
  }
  
  public synchronized void clear()
  {
    sendCmd("clear\n");
  }

  public synchronized void text( int x, int y, String str )
  {
    sendCmd("text " + x + " " + y + " \"" + str + "\"\n");
  }
  
  public synchronized void close()
  {
    try 
    {
      // Make sure to leave SB in non-sketch mode, otherwise SB remote
      // doesn't work until it's rebooted...
      quitSketchMode();
      
      readThread.stop();
      socket.close();
    }
    catch( IOException e )
    {
      System.out.println( e );
    }
  }
  
  public static void main( String args[] )
  {
    SBSketcher sbSketcher = new SBSketcher( "192.168.1.101" );

    sbSketcher.clear();

    MrUtil.sleep(2000);
    
    // Simple 2-line display test
    sbSketcher.text( 1, 0, "Artist" );
    sbSketcher.text( 1, 9, "Title of Song" );

    MrUtil.sleep(2000);

    sbSketcher.close();
  }
  
  
}
